package org.tloss.web.editor.form.editors.command;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.model.IWorkbenchAdapter;
import org.eclipse.ui.views.properties.IPropertySource;
import org.tloss.web.editor.model.command.Command;
import org.tloss.web.editor.model.command.ComplexCommand;
import org.tloss.web.editor.utils.Constants;

public abstract class AbstractCommandElement implements IWorkbenchAdapter,
		IAdaptable {
	protected Command command;
	private Object parent;
	List<AbstractCommandElement> abstractCommandElements = new ArrayList<AbstractCommandElement>();
	protected IResourceChangeListener listener;

	public abstract boolean isSupportedChildren();

	public AbstractCommandElement(Command command,
			IResourceChangeListener listener) {
		this.command = command;
		this.listener = listener;
	}

	public void setParent(Object parent) {
		this.parent = parent;
	}

	public Command getCommand() {
		return command;
	}

	public void add(AbstractCommandElement commandElement) {
		if (command instanceof ComplexCommand) {
			if ((this.command.getChildren() == null || !this.command
					.getChildren().contains(commandElement.getCommand()))
					&& !abstractCommandElements.contains(commandElement)) {
				((ComplexCommand) command).addCommand(commandElement
						.getCommand());
				abstractCommandElements.add(commandElement);
				commandElement.setParent(this);
			} else {
				int index = this.command.getChildren().indexOf(
						commandElement.getCommand());
				if (index != -1 && index >= abstractCommandElements.size()) {
					abstractCommandElements.add(commandElement);
					commandElement.setParent(this);
				}
			}
		}
	}

	public void remove(AbstractCommandElement commandElement) {
		if (command != null && command instanceof ComplexCommand) {
			if (this.command.getChildren() != null
					&& this.command.getChildren().contains(
							commandElement.getCommand())
					&& abstractCommandElements.contains(commandElement)) {
				((ComplexCommand) command).removeCommand(commandElement
						.getCommand());
				commandElement.setParent(null);
				abstractCommandElements.remove(commandElement);
			}
		}
	}

	public void up(AbstractCommandElement commandElement) {
		if (command != null && command instanceof ComplexCommand) {
			if (this.command.getChildren() != null
					&& this.command.getChildren().contains(
							commandElement.getCommand())
					&& abstractCommandElements.contains(commandElement)) {
				((ComplexCommand) command).moveUpCommand(commandElement
						.getCommand());
				int index =abstractCommandElements.indexOf(commandElement);
				if(index>0){
					AbstractCommandElement element =abstractCommandElements.get(index-1);
					abstractCommandElements.set(index-1, commandElement);
					abstractCommandElements.set(index, element);
				}
			}
		}
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Object getAdapter(Class adapter) {
		if (adapter == IWorkbenchAdapter.class)
			return this;
		if (adapter == IPropertySource.class)
			return getInternalAdapter(adapter, command, listener);
		return null;
	}

	@SuppressWarnings("rawtypes")
	public abstract Object getInternalAdapter(Class adapter, Command command,
			IResourceChangeListener listener);

	@Override
	public Object[] getChildren(Object arg0) {
		if (command == null || command.getChildren() == null
				|| command.getChildren().size() == 0) {
			return Constants.EMPTY_ARRAY;
		} else {
			Object[] children = new Object[abstractCommandElements.size()];
			abstractCommandElements.toArray(children);
			return children;
		}
	}

	@Override
	public ImageDescriptor getImageDescriptor(Object arg0) {
		return Constants.RUNSCRIPT_DESCRIPTOR;
	}

	@Override
	public String getLabel(Object arg0) {
		return (command != null && command.getLabel() != null) ? command
				.getLabel() : "";
	}

	@Override
	public Object getParent(Object arg0) {
		return parent;
	}

}
